#pragma once

#include <iostream>
#include <memory>
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

// #define SELF 1

static const std::string sep = "\r\n";
static const std::string line_sep = " ";

// 添加len报头
std::string Encode(const std::string &jsonstr)
{
    int len = jsonstr.size();
    std::string lenstr = std::to_string(len);
    return lenstr + sep + jsonstr + sep;
}

// 读取有效数据
std::string Decode(std::string &packagestream)
{
    int pos = packagestream.find(sep);
    if (pos == std::string::npos)
        return std::string();
    std::string lenstr = packagestream.substr(0, pos);
    if (lenstr.empty())
        return std::string();
    int len = std::stoi(lenstr);

    int total = len + lenstr.size() + sep.size() * 2;
    if (packagestream.size() < total)
        return std::string();
    std::string jsonstr = packagestream.substr(pos + sep.size(), len);
    packagestream.erase(0, total);
    return jsonstr;
}

class Request
{
public:
    Request(int x, int y, char oper)
        : _x(x), _y(y), _oper(oper)
    {
    }

    Request()
    {
    }

    bool Serialize(std::string *out)
    {
#ifdef SELF
        std::string str_x = std::to_string(_x);
        std::string str_y = std::to_string(_y);
        std::string str_oper = std::to_string(_oper);

        *out = str_x + line_sep + str_y + line_sep + str_oper;
        return true;
#else
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        *out = s;
        return true;
#endif
    }

    bool Deserialize(const std::string &in)
    {
#ifdef SELF
        // x # y
        auto left = in.find(line_sep);
        if (left == std::string::npos)
            return false;

        auto right = in.rfind(line_sep);
        if (right == std::string::npos)
            return false;

        if (left + line_sep.size() + 1 != right)
            return false;

        std::string str_x = in.substr(0, left);
        if (str_x.empty())
            return false;

        std::string str_y = in.substr(right + line_sep.size());
        if (str_y.empty())
            return false;

        _x = std::stoi(str_x);
        _y = std::stoi(str_y);
        _oper = in[right - 1];
        return true;
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;
#endif
    }

    void SetValue(int x, int y, char oper)
    {
        _x = x;
        _y = y;
        _oper = oper;
    }

    int X()
    {
        return _x;
    }

    int Y()
    {
        return _y;
    }

    int Oper()
    {
        return _oper;
    }

    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response()
        : _result(0), _code(0), _desc("success")
    {
    }

    bool Serialize(std::string *out)
    {
#ifdef SELF
        std::string str_result = std::to_string(_result);
        std::string str_code = std::to_string(_code);

        *out = str_result + line_sep + str_code + line_sep + _desc;
        return true;
#else
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        root["desc"] = _desc;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        *out = s;
        return true;
#endif
    }

    bool Deserialize(const std::string &in)
    {
#ifdef SELF
        auto left = in.find(line_sep);
        if (left == std::string::npos)
            return false;

        auto right = in.rfind(line_sep);
        if (right == std::string::npos)
            return false;

        std::string str_result = in.substr(0, left);
        if (str_result.empty())
            return false;
        std::string str_code = in.substr(left + line_sep.size(), right);
        if (str_code.empty())
            return false;

        _result = std::stoi(str_result);
        _code = std::stoi(str_code);
        _desc = in.substr(right + line_sep.size());
        return true;
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _result = root["result"].asInt();
        _code = root["code"].asInt();
        _desc = root["desc"].asString();

        return true;
#endif
    }

    int &result()
    {
        return _result;
    }

    int &code()
    {
        return _code;
    }

    std::string &desc()
    {
        return _desc;
    }

    void PrintResult()
    {
        std::cout << "result: " << _result << ", code: " << _code << ", desc: " << _desc << std::endl;
    }

    ~Response() {}

private:
    int _result;
    int _code;
    std::string _desc;
};

class Factory
{
public:
    static std::shared_ptr<Request> BuildRequestDefault()
    {
        return std::make_shared<Request>();
    }

    static std::shared_ptr<Response> BuildResponseDefault()
    {
        return std::make_shared<Response>();
    }
};